/*
    The NeonX Library

    Copyright (c) 2013 darkcat

    Code covered by the MIT License
*/

#pragma once

//////////////////////////////////////////////////////////////////////////

#define NX_MACRO_MAX                    50

/*
    Get a string of macro
*/

#define NX_SOL(...)                     #__VA_ARGS__
#define NX_STR(...)                     NX_SOL(__VA_ARGS__)

/*
    Connect two args together
*/

#define NX_CAT(x, ...)                  x##__VA_ARGS__
#define NX_JOIN(x, ...)                 NX_CAT(x, __VA_ARGS__)

/*
    Circumvent VC __VA_ARGS__ BUG
*/

#define NX_ARGS_(...)                   __VA_ARGS__ /* Try to expand __VA_ARGS__ */
#define NX_PROXY(F, ...)                NX_ARGS_(F(__VA_ARGS__))

/*
    NX_FILTER, NX_NUMBER, NX_HELPER, NX_CONTER
*/

#include "macro/macrofilter.h"

/*
    NX_LOOP
*/

#include "macro/macroloop.h"

/*
    Get a arg or last args from __VA_ARGS__

    NX_ARGS_N(2, a, b, c, d, e)
    -->
    b

    NX_ARGS_B(2, a, b, c, d, e)
    -->
    c, d, e
*/

#define NX_ARGS_FST_(a, ...)            a
#define NX_ARGS_F1(...)                 NX_ARGS_(NX_ARGS_FST_(__VA_ARGS__))
#define NX_ARGS_LST_(a, ...)            __VA_ARGS__
#define NX_ARGS_L1(...)                 NX_ARGS_(NX_ARGS_LST_(__VA_ARGS__))

#define NX_ARGS_F2(...)                 NX_ARGS_F1(NX_ARGS_L1(__VA_ARGS__))
#define NX_ARGS_L2(...)                 NX_ARGS_L1(NX_ARGS_L1(__VA_ARGS__))

#define NX_ARGS_I(args)                 NX_ARGS_L1(args)
#define NX_ARGS_F(args, i, nxt)         nxt
#define NX_ARGS_N_E(...)                NX_ARGS_F1(__VA_ARGS__)
#define NX_ARGS_B_E(args, i, nul)       NX_ARGS_L1(args)

#define NX_ARGS_N(n, ...)               NX_LOOP(n, NX_ARGS_F, NX_ARGS_I, NX_ARGS_N_E, , __VA_ARGS__)
#define NX_ARGS_B(n, ...)               NX_LOOP(n, NX_ARGS_F, NX_ARGS_I, NX_ARGS_B_E, , __VA_ARGS__)

/*
    Recursive call for function(a, b)

    NX_RECUR(9, f, nul, c)
    -->
    f(c, f(c, f(c, f(c, f(c, f(c, f(c, f(c, f(c, nul)))))))))
*/

#define NX_RECUR_E(args, i, nul)        NX_ARGS_F1(args)(NX_ARGS_L1(args), nul)
#define NX_RECUR_F(args, i, nxt)        NX_ARGS_F1(args)(NX_ARGS_L1(args), nxt)
#define NX_RECUR_I(args)                args

#define NX_RECUR(n, f, nul, ...)        NX_LOOP(n, NX_RECUR_F, NX_RECUR_I, NX_RECUR_E, nul, f, __VA_ARGS__)

/*
    Iteratively call for function(a, b)

    NX_ITERA(f, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
    -->
    f(1, f(2, f(3, f(4, f(5, f(6, f(7, f(8, f(9, 0)))))))))
*/

#define NX_ITERA_E(args, i, nul)        NX_ARGS_F1(args)(NX_ARGS_L1(args), nul)
#define NX_ITERA_F(args, i, nxt)        NX_ARGS_F1(args)(NX_ARGS_F2(args), nxt)
#define NX_ITERA_I(args)                NX_ARGS_F1(args),NX_ARGS_L2(args)

#define NX_ITERA_N(n, f, nul, ...)      NX_LOOP(n, NX_ITERA_F, NX_ITERA_I, NX_ITERA_E, nul, f, __VA_ARGS__)
#define NX_ITERA(f, nul, ...)           NX_ITERA_N(NX_CONTER(__VA_ARGS__), f, nul, __VA_ARGS__)

/*
    Reverse args

    NX_REVERSE(1, 2, 3, 4, 5, 6, 7, 8, 9)
    -->
    9, 8, 7, 6, 5, 4, 3, 2, 1
*/

#define NX_REVERSE_E(args, i, nul)      args
#define NX_REVERSE_F(args, i, nxt)      nxt, NX_ARGS_F1(args)

#define NX_REVERSE(...)                 NX_LOOP(NX_CONTER(__VA_ARGS__), NX_REVERSE_F, NX_ARGS_L1, NX_REVERSE_E, , __VA_ARGS__)

/*
    Limit the count of args

    NX_LIMIT(3, a, b, c, d, e, f)
    -->
    a, b, c
*/

#define NX_LIMIT_E(args, i, nul)        NX_ARGS_F1(args)
#define NX_LIMIT_F(args, i, nxt)        NX_ARGS_F1(args), nxt

#define NX_LIMIT(n, ...)                NX_LOOP(n, NX_LIMIT_F, NX_ARGS_L1, NX_LIMIT_E, , __VA_ARGS__)

/*
    Clone content for times
    
    NX_CLONE(7, con)
    -->
    con con con con con con con

    NX_CLONE(8, c, |)
    -->
    c| c| c| c| c| c| c| c

    NX_CLONE(6, c, ,)
    -->
    c, c, c, c, c, c
*/

#define NX_CLONE_E(args, i, nul)        nul
#define NX_CLONE_F(args, i, nxt)        NX_ARGS_(args) nxt

#define NX_CLONE(n, con, ...)           NX_LOOP(n, NX_CLONE_F, NX_ARGS_, NX_CLONE_E, con, NX_ARGS_(con)__VA_ARGS__)

/*
    Addition Subtraction

    NX_ADD(3, 4)
    -->
    7

    NX_SUB(5, 3)
    -->
    2
*/

#define NX_ADD(num1, num2)              NX_CONTER(NX_CLONE(num1, -, ,),NX_CLONE(num2, -, ,))
#define NX_SUB(num1, num2)              NX_CONTER(NX_ARGS_B(num2, NX_CLONE(num1, -, ,)))

#define NX_INC(num)                     NX_ADD(num, 1)
#define NX_DEC(num)                     NX_SUB(num, 1)

/*
    Compare two numbers

    NX_LESS(3, 4, Yes, No)
    -->
    Yes

    NX_MORE(3, 4, Yes, No)
    -->
    No

    NX_EQUA(3, 4, Yes, No)
    -->
    No
*/

#define NX_LESS_NUMBER(num, y, n)       NX_REVERSE(NX_LIMIT(NX_MACRO_MAX, NX_CLONE(num, n, ,),NX_CLONE(9, y, ,)))
#define NX_MORE_NUMBER(num, y, n)       NX_REVERSE(NX_LIMIT(NX_MACRO_MAX, NX_CLONE(NX_DEC(num), y, ,),NX_CLONE(9, n, ,)))

#define NX_LESS(num1, num2, y, n)       NX_HELPER(NX_CLONE(num2, -, ,), NX_LESS_NUMBER(num1, y, n))
#define NX_MORE(num1, num2, y, n)       NX_HELPER(NX_CLONE(num2, -, ,), NX_MORE_NUMBER(num1, y, n))
#define NX_EQUA(num1, num2, y, n)       NX_MORE(num1, num2, n, NX_LESS(num1, num2, n, y))

/*
    Automatically match the number of parameters

    NX_CALL(f, 1, 2, 3, 4, 5, 6, 7, 8, 9)
    -->
    f9(1, 2, 3, 4, 5, 6, 7, 8, 9)
*/

#define NX_CALL_E(f)                    NX_ARGS_(NX_JOIN(f, 0)())
#define NX_CALL_F(f, ...)               NX_ARGS_(NX_JOIN(f, NX_CONTER(__VA_ARGS__))(__VA_ARGS__))
#define NX_CALL(...)                    NX_ARGS_(NX_JOIN(NX_CALL_, NX_LESS(1, NX_CONTER(__VA_ARGS__), F, E))(__VA_ARGS__))
